package com.myblockchain.controller;

import com.alibaba.fastjson.JSON;
import com.myblockchain.service.BlockService;
import com.myblockchain.service.P2PService;
import com.myblockchain.service.WalletService;
import com.myblockchain.service.impl.P2PServiceImpl;
import com.myblockchain.service.model.Block;
import com.myblockchain.service.model.Message;
import com.myblockchain.service.model.Transaction;
import com.myblockchain.service.model.Wallet;
import com.myblockchain.viewobject.WalletVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

/**
 * @author Liu
 */

@RequestMapping("/block")
@Controller
@CrossOrigin(allowCredentials = "true",origins = {"*"})
public class BlockController {

    @Autowired
    private BlockService blockService;

    @Autowired
    private WalletService walletService;

    @Autowired
    private P2PService p2PService;

    public static final String CONTENT_TYPE_FORMED= "application/x-www-form-urlencoded";
    /**
     * 挖矿
     * @param toAddress
     * @return
     */
    @RequestMapping(value = "/mine",method = {RequestMethod.POST}, consumes = CONTENT_TYPE_FORMED)
    @ResponseBody
    public Object mine(@RequestParam(name = "address")String toAddress){
        Wallet wallet = blockService.findWallet(toAddress);
        if (wallet == null){
            return "钱包不存在";
        }
        Block newBlock = blockService.mine(toAddress);
        if (newBlock == null){
            return "挖矿失败";
        }

        Block[] blocks = {newBlock};
        String msg = JSON.toJSONString(blocks);
        p2PService.broadcastNewBlock(msg);
        return "产生新的区块"+JSON.toJSONString(newBlock);
    }

    /**
     * 查询钱包余额
     * @param walletAdd
     * @return
     */
    @RequestMapping(value = "/getBalance",method = {RequestMethod.GET})
    @ResponseBody
    public Object queryWallet(@RequestParam(name = "address")String walletAdd){
        return blockService.getWalletBalance(walletAdd);
    }

    /**
     * 查询已经打包的交易
     * @return
     */
    @RequestMapping(value = "/getPackedTransaction",method = {RequestMethod.GET})
    @ResponseBody
    public Object queryPacked(){
        return blockService.findPackedTransactionList();
    }

    /**
     * 创建钱包
     * @return
     */
    @RequestMapping(value = "/createWallet",method = {RequestMethod.GET})
    @ResponseBody
    public WalletVO createWallet(){
        Wallet wallet = blockService.createWallet();
        Wallet[] wallets = {Wallet.builder()
                .publicKey(wallet.getPublicKey())
                .build()};
        p2PService.broadcastNewWallet(JSON.toJSONString(wallets));
        return convertFromWalletModel(wallet);
    }


    /**
     * 查询区块链信息
     * @return
     */
    @RequestMapping(value = "/chain",method = {RequestMethod.GET})
    @ResponseBody
    public Object getChainInfo(){
        return blockService.getBlockChain();
    }

    /**
     * 发起一笔新的交易
     * @return
     */
    @RequestMapping(value = "/newtx",method = {RequestMethod.POST})
    @ResponseBody
    public Object startTx(@RequestParam(name = "sender")String sender,
                          @RequestParam(name = "receiver")String receiver,
                          @RequestParam(name = "amount")Integer amount){
        Wallet senderWallet = blockService.findWallet(sender);
        Wallet receiverWallet = blockService.findWallet(receiver);

        if (senderWallet == null || receiverWallet == null){
            return "钱包不存在";
        }
        Transaction newTx = blockService.createTransaction(senderWallet, receiverWallet, amount);
        if (newTx == null){
            return "交易创建失败";
        }else {
            Transaction[] transactions = {newTx};
            p2PService.broadcastNewTransaction(JSON.toJSONString(transactions));
        }
        return newTx;
    }

    private WalletVO convertFromWalletModel(Wallet wallet){
        WalletVO walletVO = new WalletVO();
        BeanUtils.copyProperties(wallet,walletVO);
        walletVO.setAddress(walletService.getWalletAddress(wallet.getPublicKey()));
        walletVO.setHashPublicKey(walletService.hashPubKey(wallet.getPublicKey()));
        return walletVO;
    }
}
